<?php

/**
 * 产生高斯分布的随机数
 *
 * @param float $mean 平均值
 * @param float $standardDeviation 标准差
 * @return float
 */
function normalDistribution(float $mean, float $standardDeviation): float {
    // Box-Muller
    $U1 = mt_rand() / mt_getrandmax();
    do {
        $U2 = mt_rand() / mt_getrandmax();
    } while ($U2 <= 0.0);
    $R = sqrt(-2.0 * log($U2));
    $THETA = 2.0 * M_PI * $U1;
    $Z = $R * cos($THETA);
    return $mean + ($Z * $standardDeviation);
}

/**
 * 产生MA模型序列
 *
 * @param array $params MA模型的参数
 * @param int $length 长度
 * @param float $standardDeviation 噪声标准差
 * @return float[]
 */
function createMASequence(array $params, int $length, float $standardDeviation): array {
    $result = [];
    $noise = [];
    for ($i = 0; $i < $length; $i++) {
        $noise[$i] = normalDistribution(0, $standardDeviation);
        $result[$i] = 0;
        for ($j = 0; $j < count($params); $j++) {
            if ($i - $j - 1 < 0) {
                break;
            }
            $result[$i] += $noise[$i - $j - 1] * $params[$j];
        }
    }
    return $result;
}

/**
 * 产生AR模型序列
 *
 * @param array $params AR模型的参数
 * @param int $length 长度
 * @param float $standardDeviation 噪声标准差
 * @return float[]
 */
function createARSequence(array $params, int $length, float $standardDeviation): array {
    $result = [];
    for ($i = 0; $i < $length; $i++) {
        $result[$i] = 0;
        for ($j = 0; $j < count($params); $j++) {
            if ($i - $j - 1 < 0) {
                break;
            }
            $result[$i] += $params[$j] * $result[$i - $j - 1];
        }
        $result[$i] += normalDistribution(0, $standardDeviation);
    }
    return $result;
}

/**
 * 输出使用示例信息
 *
 * @return void
 */
function echoExample() {
    $example = <<<EXAMP
-t 指定类型，ar或ma
-p 指定参数，用“,”隔开
-s 指定标准差
-l 指定长度
示例：
php gen.php -t ar -p 1,2,3 -s 0.01 -l 100

EXAMP;
    echo $example;
}

$commandPrams = getopt('t:p:s:l:');
if (!isset($commandPrams['t']) || !in_array($commandPrams['t'], ['ar', 'ma'])) {
    echo '-t 参数取值必须是 ar 或 ma' . PHP_EOL;
    echoExample();
    exit(-1);
}
if (!isset($commandPrams['p'])) {
    echo '-p 参数需要指定' . PHP_EOL;
    echoExample();
    exit(-1);
}
if (!isset($commandPrams['s'])) {
    echo '-s 参数需要指定' . PHP_EOL;
    echoExample();
    exit(-1);
}
if ($commandPrams['s'] <= 0) {
    echo '-s 参数需要大于0' . PHP_EOL;
    echoExample();
    exit(-1);
}
if (!isset($commandPrams['l'])) {
    echo '-l 参数需要指定' . PHP_EOL;
    echoExample();
    exit(-1);
}
if ($commandPrams['l'] <= 0) {
    echo '-l 参数需要大于0' . PHP_EOL;
    echoExample();
    exit(-1);
}
switch ($commandPrams['t']) {
    case 'ar':
        foreach (createARSequence(explode(',', $commandPrams['p']), $commandPrams['l'], $commandPrams['s']) as $item) {
            echo sprintf('%.9f', $item) . PHP_EOL;
        }
        break;
    case 'ma':
        foreach (createMASequence(explode(',', $commandPrams['p']), $commandPrams['l'], $commandPrams['s']) as $item) {
            echo sprintf('%.9f', $item) . PHP_EOL;
        }
        break;
    default:
        echo '不存在的类型：' . $commandPrams['t'] . PHP_EOL;
        exit(-1);
}
